
# 从qtpy库导入QtCore和QtGui模块
from qtpy import QtCore, QtGui
# 从qtpy.QtWidgets模块导入QComboBox和QCompleter类
from qtpy.QtWidgets import QComboBox, QCompleter


class EnumComboBox(QComboBox):
    """
    自定义的枚举组合框类，继承自QComboBox。
    提供了自动补全功能，并在文本编辑和选项改变时发出信号。
    """
    # 定义一个信号，当选项改变时发出，携带当前选项的文本
    changeCallback = QtCore.Signal(str)
    # 定义一个信号，当文本编辑时发出，携带编辑后的文本
    textChangedCallback = QtCore.Signal(str)

    def __init__(self, values=None, parent=None):
        """
        初始化枚举组合框。

        :param values: 组合框的初始选项列表，默认为None
        :param parent: 父控件，默认为None
        """
        # 调用父类的构造函数
        super(EnumComboBox, self).__init__(parent)

        # 如果未提供选项列表，则初始化为空列表
        if values is None:
            values = []
        # 设置焦点策略，这里存在类 'Qt' 的未解析的特性引用问题
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        # 设置组合框为可编辑状态
        self.setEditable(True)
        # 创建一个自动补全器，并将其父控件设置为当前组合框
        self.completer = QCompleter(self)

        # 始终显示所有补全选项，这里存在类 'QCompleter' 的未解析的特性引用问题
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        # 创建一个排序过滤代理模型，并将其父控件设置为当前组合框
        self.pFilterModel = QtCore.QSortFilterProxyModel(self)
        # 设置过滤时不区分大小写，这里存在类 'Qt' 的未解析的特性引用问题
        self.pFilterModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)

        # 注释掉的代码：设置插入策略为不插入新项
        #self.setInsertPolicy(self.NoInsert)

        # 将自动补全器的弹出窗口设置为组合框的视图
        self.completer.setPopup(self.view())

        # 为组合框设置自动补全器
        self.setCompleter(self.completer)

        # 连接文本编辑信号到onTextEdited方法
        self.lineEdit().textEdited[str].connect(self.onTextEdited)
        # 连接自动补全器的激活信号到setTextIfCompleterIsClicked方法
        self.completer.activated.connect(self.setTextIfCompleterIsClicked)

        # 创建一个标准项模型
        self.model = QtGui.QStandardItemModel()
        # 遍历选项列表，将每个选项添加到模型中
        for i, value in enumerate(values):
            item = QtGui.QStandardItem(value)
            self.model.setItem(i, 0, item)
        # 为组合框设置模型
        self.setModel(self.model)
        # 设置模型的列索引
        self.setModelColumn(0)
        # 连接当前索引改变信号到onIndexChanged方法
        self.currentIndexChanged.connect(self.onIndexChanged)

    def onTextEdited(self, text):
        """
        当组合框的文本被编辑时调用。
        设置过滤字符串，并发出文本改变信号。

        :param text: 编辑后的文本
        """
        self.pFilterModel.setFilterFixedString(text)
        self.textChangedCallback.emit(text)

    def onReturnPressed(self):
        """
        当按下回车键时调用。
        发出选项改变信号，携带当前文本。
        """
        self.changeCallback.emit(self.currentText())

    def onIndexChanged(self, index):
        """
        当组合框的当前索引改变时调用。
        发出选项改变信号，携带当前文本。

        :param index: 改变后的索引
        """
        self.changeCallback.emit(self.currentText())

    def setModel(self, model):
        """
        为组合框设置模型，并更新自动补全器的模型。

        :param model: 要设置的模型
        """
        # 调用父类的setModel方法
        super(EnumComboBox, self).setModel(model)
        # 为排序过滤代理模型设置源模型
        self.pFilterModel.setSourceModel(model)
        # 为自动补全器设置模型
        self.completer.setModel(self.pFilterModel)

    def setModelColumn(self, column):
        """
        设置模型的列索引，并更新自动补全器和排序过滤代理模型的列索引。

        :param column: 要设置的列索引
        """
        self.completer.setCompletionColumn(column)
        self.pFilterModel.setFilterKeyColumn(column)
        # 调用父类的setModelColumn方法
        super(EnumComboBox, self).setModelColumn(column)

    def view(self):
        """
        返回自动补全器的弹出窗口。

        :return: 自动补全器的弹出窗口
        """
        return self.completer.popup()

    def index(self):
        """
        返回组合框的当前索引。

        :return: 当前索引
        """
        return self.currentIndex()

    def setTextIfCompleterIsClicked(self, text):
        """
        当自动补全器中的选项被点击时调用。
        根据文本查找对应的索引，并设置组合框的当前索引。

        :param text: 点击的选项文本
        """
        if text:
            index = self.findText(text)
            self.setCurrentIndex(index)


if __name__ == "__main__":
    # 导入sys模块，用于处理命令行参数
    import sys
    # 从qtpy.QtWidgets模块导入QApplication类
    from qtpy.QtWidgets import QApplication
    # 创建一个QApplication实例
    a = QApplication(sys.argv)

    def clb(string):
        """
        回调函数，用于打印接收到的字符串。

        :param string: 接收到的字符串
        """
        print(string)

    # 创建一个EnumComboBox实例，并传入初始选项列表
    w = EnumComboBox(["A", "B", "TEST"])
    # 设置组合框为不可编辑状态
    w.setEditable(False)
    # 连接选项改变信号到回调函数
    w.changeCallback.connect(clb)

    # 显示组合框
    w.show()

    # 进入应用程序的事件循环，并在关闭窗口时退出
    sys.exit(a.exec_())